package cn.bouncyslime.algorithms.stack.infixToPostfix;

import cn.bouncyslime.slime.util.BigDecimalUtils;

import java.util.*;

/**
 * 可以用来计算后缀表达式，生成正确的计算结果，考虑运算符优先级
 * @author 张一卓
 */
public class CalculatePostfix {
	
	private List<String> operatorList = new ArrayList<>();
	
	public CalculatePostfix() {
		operatorList.add("(");
		operatorList.add(")");
		operatorList.add("+");
		operatorList.add("-");
		operatorList.add("*");
		operatorList.add("/");
	}

	/**
	 * @param input 后缀表达式数组
	 * @return 计算结果
	**/
	public String calculate(String[] input) {
		LinkedList<String> list = new LinkedList<>(Arrays.asList(input));;
		while (list.size()!=1) {
			for (int i = 0; i < list.size(); i++) {
				if (operatorList.contains(list.get(i))) {
					switch (list.get(i)) {
						case "+":
							list.set(i, Double.toString(BigDecimalUtils.add(list.get(i - 2), list.get(i - 1))));
							break;
						case "-":
							list.set(i, Double.toString(BigDecimalUtils.subtract(list.get(i - 2), list.get(i - 1))));
							break;
						case "*":
							list.set(i, Double.toString(BigDecimalUtils.multiply(list.get(i - 2), list.get(i - 1))));
							break;
						case "/":
							list.set(i, Double.toString(BigDecimalUtils.divide(list.get(i - 2), list.get(i - 1))));
							break;
					}
					list.remove(i-1); list.remove(i-2);
					break;
				}
			}
		}
		return list.get(0);
	}
	
	/**
	 * 通过栈进行计算，更加高效
	 * @param input 后缀表达式数组
	 * @return 计算结果
	 */
	public String calculate2(String[] input) {
		Deque<String> stack = new LinkedList<>();
		for (String s : input) {
			if (!operatorList.contains(s)) {
				stack.push(s);
			} else {
				switch (s) {
					case "+":
						stack.push(Double.toString(BigDecimalUtils.add(stack.pop(), stack.pop())));
						break;
					case "-":
						stack.push(Double.toString(BigDecimalUtils.subtract(stack.pop(), stack.pop())));
						break;
					case "*":
						stack.push(Double.toString(BigDecimalUtils.multiply(stack.pop(), stack.pop())));
						break;
					case "/":
						stack.push(Double.toString(BigDecimalUtils.divide(stack.pop(), stack.pop())));
						break;
				}
			}
		}
		return stack.pop();
	}
	
	public static void main(String[] args) {
		String input = "3.6 + 6 * 2.1 + ( 8 * 1.2 + 2 )";
//		String input = "3.6 - 2 * 5 + ( 8 * 12 - 2 ) + 12 / 3.2";
		InfixToPostfix2 infixToPostfix = new InfixToPostfix2(input);
		System.out.println(new CalculatePostfix().calculate(infixToPostfix.change()));
		System.out.println(new CalculatePostfix().calculate2(infixToPostfix.change()));
	}
}